package fr.cephb.operonj.tools.cmdline.remapper;

import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.Transaction;

import fr.cephb.operonj.core.bio.Observed;
import fr.cephb.operonj.core.je.PrimaryDB;


public class RsSaxHandler
	extends DefaultHandler
	{
	public static final Logger LOG= Logger.getLogger("fr.cephb.operonj");
	private static final Pattern SIMPLE_MUTATION_REGEX=Pattern.compile("[ATGCatgc]/[ATGCatgc]"); 
	//private static final String NS="http://www.ncbi.nlm.nih.gov/SNP/docsum";
	private StringBuilder builder=null;
	private String rsId=null;
	private String seq5=null;
	private Observed observed=null;
	private String seq3=null;
	private Set<String> handle= new HashSet<String>();
	private boolean inSequence=false;
	private PrimaryDB<String, String> rs2snp;
	private SNPToInfoDB name2info;
	private Transaction txn;
	public RsSaxHandler(
			Transaction txn,
			PrimaryDB<String, String> rs2snp,
			SNPToInfoDB name2info
			
			)
		{
		this.txn=txn;
		this.rs2snp=rs2snp;
		this.name2info=name2info;
		
		clear();
		}
	
	private void clear()
		{
		rsId=null;
		seq5=null;
		observed=null;
		seq3=null;
		inSequence=false;
		handle.clear();
		}
	
	@Override
	public void startDocument() throws SAXException
		{
		clear();
		this.builder=null;
		}
	
	@Override
	public void startElement(
			String uri, String localName, String qName,
			Attributes attributes) throws SAXException
		{
		if(localName.equals("Rs"))
			{
			rsId= "rs"+attributes.getValue("rsId");
			}
		else if(localName.equals("Ss"))
			{
			String s= attributes.getValue("handle");
			if(s!=null) this.handle.add(s);
			}
		else if(localName.equals("Seq5")||
				localName.equals("Observed") ||
				localName.equals("Seq3"))
			{
			assert(rsId!=null);
			this.builder= new StringBuilder();
			}
		else if(localName.equals("Sequence") &&
				attributes.getValue("exemplarSs")!=null)
			{
			assert(rsId!=null);
			assert(seq5==null);
			inSequence=true;
			}
		}
	@Override
	public void endElement(String uri, String localName, String qName) 
			throws SAXException
		{
		if(localName.equals("Rs"))
			{
			assert(rsId!=null);
			assert(seq5!=null);
			assert(seq3!=null);
			assert(observed!=null);
			try
				{
				String name= this.rs2snp.get(this.txn, rsId);
				if(name!=null)
					{
					SNPInfo info = this.name2info.get(this.txn, name);
					if(info!=null)
						{
						
						if(info.ncbiSeq5.length()>0)
							{
							assert(info.rsId.equals(rsId));
							assert(info.ncbiSeq5.equals(seq5));
							assert(info.ncbiSeq3.equals(seq3));
							assert(info.ncbiObserved.equals(observed));
							}
						info.ncbiSeq5=seq5;
						info.ncbiObserved=observed;
						info.ncbiSeq3=seq3;
						info.ncbiHandles.addAll(this.handle);
						if(this.name2info.put(this.txn,  name, info)!=OperationStatus.SUCCESS)
							{
							throw new RuntimeException("Cannot insert "+rsId);
							}
						}
					}
				}
			catch (DatabaseException err)
				{
				throw new SAXException(err);
				}
			clear();
			}
		else if(inSequence && localName.equals("Seq5") )
			{
			if(seq5!=null)
				{
				System.err.println(""+rsId+" "+this.builder);
				}
			assert(seq5==null);
			seq5=this.builder.toString();
			}
		else if(inSequence && localName.equals("Seq3"))
			{
			assert(seq3==null);
			seq3=this.builder.toString();
			}
		else if(inSequence && localName.equals("Observed"))
			{
			assert(observed==null);
			observed=new Observed(this.builder.toString());
			if(!SIMPLE_MUTATION_REGEX.matcher(observed.asString()).matches())
				{
				//TODO LOG.info("Non basic mutation rs"+rsId+" "+observed);
				}
			}
		else if(localName.equals("Sequence"))
			{
			inSequence=false;
			}
		this.builder=null;
		}
	
	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException
		{
		if(this.builder!=null) this.builder.append(ch,start,length);
		}
	

	}
